from gameobjects import *
from pyglet.gl import *
import math
import random
import data

numSegs = 6 
radius = 40 
road_width = 20
error_margin = 0
far_plane = 300

class Map:
    path_tex = pyglet.image.load(data.filepath('pathtex.jpg')).get_texture()
    shadow_tex  = pyglet.image.load(data.filepath('shadow_rgba.png')).get_texture()
    def __init__(self):
        self.verts = ()
        self.objs = ()
        #initializing the control points
        self.show_shadow = True
        self.cp = [radius]
        while self.cp[len(self.cp)-1] < far_plane:
            self.addControlPoint()
        for i in xrange(len(self.cp)):
            self.addVerts(i)

        self.getObjHitList((30, 0))
#        tmp = (NPC('puzzle', [0, 0, 1]),)
#        tmp[0].setPatrol([30, 0, 1], [0, 0, 1])
#        self.objs += tmp
#        tmp = (NPC('puzzle', [0, -10, 1]),)
#        tmp[0].setPatrol([30, -20, 1], [0, -10, 1])
#        self.objs += tmp

    def addControlPoint(self):
        prev = self.cp[len(self.cp)-1] 
        #r = random.choice([30, 20, 40])
        r = random.randrange(30, 40, 5)
        self.cp.append(prev + r)

    def isTouching(self, pos):
        for i in xrange(len(self.cp)):
            (cx, cy) = (0, -self.cp[i])
            r = self.cp[i]
            if(i > 0):
                r = self.cp[i] - self.cp[i-1]
                cy = -(self.cp[i-1] * 2 + r)

            if i%2 == 0:#left curve
                r1 = r - error_margin
                r2 = r + road_width
            else:#right curve
                r1 = r - road_width - error_margin 
                r2 = r 
            d_2 = (pos[0] * pos[0]) + (cy-pos[1]) * (cy-pos[1])
            r1_2 = r1 * r1
            r2_2 = r2 * r2
            #print "d_2 > r1_2: ", d_2 >= r1_2, "d_2 < r2_2: ", d_2 <= r2_2, d_2, r1_2, r2_2 
            #print pos, i
            if d_2 >= r1_2 and d_2 <= r2_2:
                if i & 1 and pos[0] <= 0:
                    self.show_shadow = True
                    return True
                elif i & 1 == 0 and pos[0] > 0:
                    self.show_shadow = True
                    return True
        self.show_shadow = False
        if pos[2] > 0.5: #don't check if the object is in a jump
            return True
        return False

    def getObjHitList(self, pos):
        #function to check if hero is colliding with other game objects
        #returns a list of objects that we might be hitting
        hit_list = ()
        new_objs = ()
        for obj in self.objs:
            obj.update()
            if obj.obj.pos[1] > (pos[1]+radius/3): #this is beyond the player delete it
                continue
            if obj.obj.pos[1] > (pos[1]-far_plane):
                if obj.sphereCollide(pos, 0.5):
                    hit_list += (obj,)                
                    if obj.delete_on_collision:
                        continue
            new_objs += (obj,)
        self.objs = new_objs
        #add objects if we can (adding objects at random)
        while len(self.objs) < 5:
            elems_per_v = 6 #2 vertices (x,y,z) added 
            num_elems = (numSegs) * elems_per_v #numSegs+1 times 
            num_curves = random.choice([2, 3])
            num_elems = len(self.verts) - (num_curves*numSegs) * elems_per_v 
            tmp = self.verts[num_elems:]
            indx = random.randrange(0, 2*numSegs, 2)
            p1 = (tmp[indx*3], tmp[indx*3+1], tmp[indx*3+2])
            indx+= 1
            p2 = (tmp[indx*3], tmp[indx*3+1], tmp[indx*3+2])
            type = random.choice(['static', 'patrol'])
            if type == 'static':
                self.addObj('spikes', p1, p1)
            else:
                enemy = random.choice(['spikes', 'bat', 'bat', 'bat', 'puzzle']) 
                p = (pos[0], pos[1], tmp[indx*3+2]) #align the z value based on map verts
                dir = random.choice([False, False, True]) #2:1 ratio for this occurance
                if dir and enemy == 'bat':
                    self.addObj(enemy, p1, p) #charge at player
                else:
                    self.addObj(enemy, p2, p1)
        
        return hit_list

    def prune(self, pos):
        if pos[1] - far_plane < self.verts[len(self.verts)-2]: #len(self.verts)-1 gives z coord of last vertex
            elems_per_v = 6 #2 vertices (x,y,z) added 
            num_elems = (numSegs) * elems_per_v #numSegs+1 times 
            self.verts = self.verts[num_elems:]
            self.addControlPoint()
            self.addVerts(len(self.cp)-1)

    def addObj(self, type, p1, p2):
        obj = NPC(type, [p1[0], p1[1], p1[2]])
        obj.setPatrol(p1, p2)
        self.objs += (obj, )

    def addVerts(self, i):
        dt = math.pi/numSegs
        (cx, cy) = (0, -self.cp[i])
        r = self.cp[i] #true only for the first control point
        if(i > 0):
           r = self.cp[i] - self.cp[i-1]
           cy = -(self.cp[i-1] * 2 + r)

        angle = 0 
        rw = road_width
        if i & 1:
            angle = math.pi;
            rw = -road_width

        for j in xrange(numSegs+1):
            y1 = cy + r * math.cos(angle)
            x1 = cx + r * math.sin(angle)
            y2 = cy + (r + rw) * math.cos(angle)
            x2 = cx + (r + rw) * math.sin(angle)
            if rw > 0:
                self.verts += (x1, y1, 0.5)
                self.verts += (x2, y2, 0.5)
            else:
                self.verts += (x2, y2, 0.5)
                self.verts += (x1, y1, 0.5)
            angle += dt

    def updateMap(self):
        pass

    def draw(self, p): 
        glColor3f(1, 1, 1)
        #draw the path
        tex = ()
        for i in xrange(len(self.verts)/6):
            if i & 1:
                tex +=  (0.1, 0, 0.9, 0)
            else:
                tex +=  (0.1, 1, 0.9, 1)
        glBindTexture(GL_TEXTURE_2D, Map.path_tex.id)
        pyglet.graphics.draw(len(self.verts)/3, pyglet.gl.GL_QUAD_STRIP, ('v3f', self.verts), ('t2f', tex))
        if self.show_shadow:
            glColor4f(1.0, 1.0, 1.0, 0.5)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            glEnable(GL_BLEND)
            glBindTexture(GL_TEXTURE_2D, Map.shadow_tex.id)
            w = 3
            h = 3
            pyglet.graphics.draw(4, pyglet.gl.GL_POLYGON, 
                    ('v3f', (p[0]-w, p[1]+h, 0.6, p[0]+w, p[1]+h, 0.6,p[0]+w, p[1]-h, 0.6, p[0]-w, p[1]-h, 0.6)),
                    ('t2f', (0, 0, 1, 0, 1, 1, 0, 1)))
            glDisable(GL_BLEND)
        glColor4f(1, 1, 1, 1)
        #draw the objects
        for obj in self.objs:
            if obj.obj.pos[1] > (p[1] - far_plane): 
                obj.draw()
